/*
 * twim.h
 *
 *  Created on: Aug 1, 2013
 *      Author: Ken Arok
 *
 *      Revision history:
 *      ---------------------------------------------------------
 *      Date			|	Revised by		|	Description
 *      ---------------------------------------------------------
 *      1. Aug 1, 2013	|	Yosef			| New establishment
 *
 *
 *
 * \brief Hardware Abstraction Layer of Two Wire Interface Master UC3C0512C
 *
 * Copyright (c) 2013 PT Hanindo Automation Solutions. All rights reserved.
 *
 */

#include "config_board.h"

#if BOARD_1_0_USED

#ifndef TWIM_H_
#define TWIM_H_

#include <avr32/io.h>
#include <stdint.h>
#include "compiler.h"
#include "sysclk.h"

#ifdef __cplusplus
extern "C" {
#endif

//! TWI Standard Mode
#define TWI_STD_MODE_SPEED      (100000 /* kbit/s */)
//! TWI Fast Mode
#define TWI_FAST_MODE_SPEED     (400000 /* kbit/s */)

//! Status Clear Register Mask for No Acknowledgments
#define AVR32_TWIM_SCR_NAK_MASK (AVR32_TWIM_SCR_ANAK_MASK | AVR32_TWIM_SCR_DNAK_MASK)
//! Status Register Mask for No Acknowledgments
#define AVR32_TWIM_SR_NAK_MASK  (AVR32_TWIM_SR_ANAK_MASK | AVR32_TWIM_SR_DNAK_MASK)
//! Interrupt Enable Register Mask for No Acknowledgments
#define AVR32_TWIM_IER_NAK_MASK (AVR32_TWIM_IER_ANAK_MASK | AVR32_TWIM_IER_DNAK_MASK)
//! Frequently used Interrupt Enable Register Mask
#define AVR32_TWIM_IER_STD_MASK (AVR32_TWIM_IER_NAK_MASK | AVR32_TWIM_IER_ARBLST_MASK)
//! Frequently used Status Clear Register Mask
#define AVR32_TWIM_SR_STD_MASK  (AVR32_TWIM_SR_NAK_MASK | AVR32_TWIM_SR_ARBLST_MASK)


// These defines are missing from or wrong in the tool chain header file ip_xxx.h or part.h
#if !defined(AVR32_TWIM0_GROUP)
	#define AVR32_TWIM0_GROUP         25
#else
	#warning "Duplicate define(s) to remove from the ASF"
#endif

#if !defined(AVR32_TWIM1_GROUP)
	#define AVR32_TWIM1_GROUP         26
#else
	#warning "Duplicate define(s) to remove from the ASF"
#endif
#if !defined(AVR32_TWIM2_GROUP)
	#define AVR32_TWIM2_GROUP         45
#else
	#warning "Duplicate define(s) to remove from the ASF"
#endif
#define CONF_TWIM_IRQ_LINE          AVR32_TWIM0_IRQ
#define CONF_TWIM_IRQ_GROUP         AVR32_TWIM0_GROUP
#define CONF_TWIM_IRQ_LEVEL         AVR32_INTC_INT1


/**
 * \name TWI Driver Compatibility
 * Codes for UC3 devices using TWI modules can easily be ported
 * to UC3 devices with TWIM module
 * @{
 */
#define avr32_twi_t avr32_twim_t
#define twi_options_t twim_options_t
#define twi_package_t twim_package_t
#define twi_master_init twim_master_init
#define twi_probe twim_probe
//! @}

enum twim_status_code {
	TWIM_STATUS_OK				=  0, //!< Success
	TWIM_ERR_IO_ERROR            =  -1, //!< I/O error
	TWIM_ERR_FLUSHED             =  -2, //!< Request flushed from queue
	TWIM_ERR_TIMEOUT             =  -3, //!< Operation timed out
	TWIM_ERR_BAD_DATA            =  -4, //!< Data integrity check failed
	TWIM_ERR_PROTOCOL            =  -5, //!< Protocol error
	TWIM_ERR_UNSUPPORTED_DEV     =  -6, //!< Unsupported device
	TWIM_ERR_NO_MEMORY           =  -7, //!< Insufficient memory
	TWIM_ERR_INVALID_ARG         =  -8, //!< Invalid argument
	TWIM_ERR_BAD_ADDRESS         =  -9, //!< Bad address
	TWIM_ERR_BUSY                =  -10, //!< Resource is busy
	TWIM_ERR_BAD_FORMAT          =  -11, //!< Data format not recognized
	TWIM_OPERATION_IN_PROGRESS	= -128,
};

typedef enum twim_status_code twim_status_code_t;

/**
 * \brief Status Codes for TWI Transfer
 * @{
 */
enum twim_transfer_status{
	TWI_SUCCESS = 0,            //!< \brief TWI Transaction Success
	TWI_INVALID_ARGUMENT = -1,  //!< \brief Invalid Argument Passed
	TWI_ARBITRATION_LOST = -2,  //!< \brief Bus Arbitration Lost
	TWI_NO_CHIP_FOUND = -3,     //!< \brief Slave Not Found
	TWI_RECEIVE_NACK = -4,      //!< \brief Data No Acknowledgement Received
	TWI_SEND_NACK = -5,         //!< \brief Data No Acknowledgement Send
	TWI_INVALID_CLOCK_DIV = -6  //!< \brief Invalid Clock Divider Value
};

typedef enum twim_transfer_status twim_transfer_status_t;

/**
 * \brief Input parameters when initializing the twim module mode
 */
typedef struct {
	//! The PBA clock frequency.
	uint32_t pba_hz;
	//! The baudrate of the TWI bus.
	uint32_t speed;
	//! The desired address.
	uint32_t chip;
	//! SMBUS mode
	bool smbus;
} twim_options_t;

/**
 * \brief Information concerning the data transmission
 */
typedef struct {
	//! TWI chip address to communicate with.
	uint32_t chip;
	//! TWI address/commands to issue to the other chip (node).
	uint8_t addr[3];
	//! Length of the TWI data address segment (1-3 bytes).
	uint8_t addr_length;
	//! Where to find the data to be written.
	void *buffer;
	//! How many bytes do we want to write.
	uint32_t length;
	//! Whether to wait if bus is busy (false) or return immediately (true)
	bool no_wait;
} twim_package_t;

/**
 * \brief Information concerning the data transmission
 */
typedef struct {
	//! TWI chip address to communicate with.
	uint32_t chip;
	//! Where to find the data .
	void *buffer;
	//! How many bytes do we want to transfer.
	uint32_t length;
	//! Transfer direction
	bool read;
} twim_transfer_t;


typedef volatile avr32_twi_t *twi_master_t;
typedef twi_options_t twi_master_options_t;


/**
 * \brief Enable Master Mode of the TWI.
 *
 * \param twim   Base address of the TWI instance.
 */
static inline void twim_master_enable(volatile avr32_twim_t *twim)
{
	twim->cr = AVR32_TWIM_CR_MEN_MASK;;
}

/**
 * \brief Disable Master Mode of the TWI.
 *
 * \param twim   Base address of the TWI instance.
 */
static inline void twim_master_disable(volatile avr32_twim_t *twim)
{
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;;
}

/**
 * \brief Initialize the twi master module
 *
 * \param twim              Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *opt              Options for initializing the twim module
 *                          (see \ref twim_options_t)
 * \retval STATUS_OK        Transaction is successful
 * \retval ERR_INVALID_ARG  Invalid arg resulting in wrong CWGR Exponential
 * \retval ERR_IO_ERROR     NACK is received or Bus Arbitration lost
 */
extern twim_status_code_t twim_master_init(volatile avr32_twim_t *twim, const twim_options_t *opt);

/**
 * \brief Set the twim bus speed in conjunction with the clock frequency
 *
 * \param twim              Base address of the TWIM (i.e. &AVR32_TWIM).
 * \param speed             The desired twim bus speed
 * \param pba_hz            The current running PBA clock frequency
 * \retval STATUS_OK        Transaction is successful
 * \retval ERR_INVALID_ARG  Invalid arg resulting in wrong CWGR Exponential
 */
extern twim_status_code_t twim_set_speed(volatile avr32_twim_t *twim, uint32_t speed, uint32_t pba_hz);

/**
 * \brief Test if a chip answers for a given twi address
 *
 * \param twim            Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param chip_addr       Address of the chip which is searched for
 * \retval STATUS_OK      Slave Found
 * \retval ERR_IO_ERROR   ANAK received or Bus Arbitration lost
 */
extern twim_status_code_t twim_probe(volatile avr32_twim_t *twim, uint32_t chip_addr);

/**
 * \brief Read multiple bytes from a TWI compatible slave device
 *
 * \param twim            Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param package         Package information and data
 *                        (see \ref twim_package_t)
 * \retval STATUS_OK      If all bytes were read successfully
 * \retval ERR_IO_ERROR   NACK received or Bus Arbitration lost
 */
extern twim_status_code_t twim_read_packet(volatile avr32_twim_t *twim, const twim_package_t *package);

/**
 * \brief Write multiple bytes to a TWI compatible slave device
 *
 * \param twim            Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *package        Package information and data
 *                        (see \ref twim_package_t)
 * \retval STATUS_OK      If all bytes were send successfully
 * \retval ERR_IO_ERROR   NACK received or Bus Arbitration lost
 */
extern twim_status_code_t twim_write_packet(volatile avr32_twim_t *twim, const twim_package_t *package);

/**
 * \brief Read multiple bytes from a TWI compatible slave device
 *
 * \param twim            Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *buffer         Received data
 * \param nbytes          Number of bytes to be transmitted
 * \param saddr           Slave address
 * \param tenbit          Ten bit addressing
 * \retval STATUS_OK      If all bytes were read successfully
 * \retval ERR_IO_ERROR   NACK received or Bus Arbitration lost
 */
extern twim_status_code_t twim_read(volatile avr32_twim_t *twim, uint8_t *buffer, uint32_t nbytes, uint32_t saddr, bool tenbit);

/**
 * \brief Write multiple bytes to a TWI compatible slave device
 *
 * \param twim            Base address of the TWIM (i.e. &AVR32_TWIM).
 * \param *buffer         Data to be transmitted
 * \param nbytes          Number of bytes to be transmitted
 * \param saddr           Slave address
 * \param tenbit          Ten bit addressing
 * \retval STATUS_OK      If all bytes were send successfully
 * \retval ERR_IO_ERROR   NACK received or Bus Arbitration lost
 */
extern twim_status_code_t twim_write(volatile avr32_twim_t *twim, const uint8_t *buffer, uint32_t nbytes, uint32_t saddr, bool tenbit);

/**
 * \brief Perform Chained transfers to a TWI compatible slave device
 *
 * \param twim            Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *first          Information regarding first transfer
 * \param *second         Information regarding second transfer
 *                        (see \ref twim_transfer_t)
 * \param tenbit          To enable tenbit addressing
 * \retval STATUS_OK      Chain transfer successful
 * \retval ERR_IO_ERROR   NACK received or Bus Arbitration lost
 */
extern twim_status_code_t twim_chained_transfer (volatile avr32_twim_t *twim, volatile twim_transfer_t *first, volatile twim_transfer_t *second, bool tenbit);

/**
 * \brief Compatibility with TWI Module driver for read operation
 *
 * \param twim         Base address of the TWIM (i.e. &AVR32_TWIM).
 * \param package      Package information and data
 *                     (see \ref twim_package_t)
 * \return STATUS_OK   If all bytes were read, error code otherwise
 */
static inline twim_status_code_t twi_master_read (volatile avr32_twi_t *twim, const twi_package_t *package)
{
	return (twim_read_packet (twim, package));
}

/**
 * \brief Compatibility with TWI Module drivers for write operation
 *
 * \param twim         Base address of the TWIM (i.e. &AVR32_TWI).
 * \param *package     Package information and data
 *                     (see \ref twim_package_t)
 * \return STATUS_OK   if all bytes were written, error code otherwise
 */
static inline twim_status_code_t twi_master_write (volatile avr32_twi_t *twim, const twi_package_t *package)
{
	return (twim_write_packet (twim, package));
}


/**
 * \brief Setup TWI as Master mode.
 *
 * \param twi			Base address of the TWIM (i.e. &AVR32_TWI).
 * \param *opt			Option information and data
 * \return STATUS_OK   if all bytes were written, error code otherwise
 */
static inline twim_status_code_t twi_master_setup(twi_master_t twi, twi_master_options_t *opt)
{
	twim_status_code_t status;
	
	opt->pba_hz = sysclk_get_pba_hz();
	if ((uint32_t)twi == AVR32_TWIM0_ADDRESS) {
		sysclk_enable_pba_module(SYSCLK_TWIM0);
	} 
	else if ((uint32_t)twi == AVR32_TWIM1_ADDRESS) {
		sysclk_enable_pba_module(SYSCLK_TWIM1);
	}
	status = twi_master_init(twi, (const twi_master_options_t *)opt);
	return status;
}


/**
 * \brief Disable the TWI interrupts and clear its status register
 *
 * \param twim   Base address of the TWIM (i.e. &AVR32_TWI).
 */
extern void twim_disable_interrupt (volatile avr32_twim_t *twim);

/*!
 * \brief Information about the current status of the TWI Bus
 */
extern uint8_t twim_status (void);

#ifdef __cplusplus
}
#endif

#endif /* TWIM_H_ */

#endif /* BOARD_1_0_USED */
